home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-04-13 | 21.6 KB | 1,159 lines | [TEXT/ttxt] |
- -- Part of SmallEiffel -- Read DISCLAIMER file -- Copyright (C)
- -- Dominique COLNET and Suzanne COLLIN -- colnet@loria.fr
- --
- class STRING
- --
- -- Characters strings.
- --
-
- inherit
- COMPARABLE
- redefine
- hash_code, is_equal, compare, copy, out_in_tagged_out_memory,
- fill_tagged_out_memory
- end;
-
- creation make, copy, blank, from_external
-
- feature
-
- count: INTEGER;
- -- String length.
-
- capacity: INTEGER;
- -- Capacity of the `storage'.
-
- feature {STRING}
-
- storage: C_ARRAY[CHARACTER];
- -- The place where characters are stored.
-
- feature -- Creation / Modification :
-
- make(needed_capacity: INTEGER) is
- -- Initialize the string to have at least a `needed_capacity'
- -- space of storage.
- require
- needed_capacity >= 0;
- do
- if needed_capacity > 0 then
- if capacity < needed_capacity then
- if capacity = 0 then
- storage.malloc(needed_capacity);
- else
- storage.realloc(storage,needed_capacity);
- end;
- capacity := needed_capacity;
- end;
- end;
- count := 0;
- ensure
- needed_capacity <= capacity;
- count = 0
- end;
-
- blank(nr_blanks: INTEGER) is
- -- Initialize string with `nr_blanks' blanks.
- require
- nr_blanks >= 0;
- do
- make(nr_blanks);
- count := nr_blanks;
- fill_with(' ');
- ensure
- count = nr_blanks;
- occurrences_of(' ') = count
- end;
-
- feature -- No Modification of the receiver :
-
- empty: BOOLEAN is
- -- Has string length 0?
- do
- Result := (count = 0)
- end;
-
- item, infix "@" (index: INTEGER): CHARACTER is
- -- Character at position `index'.
- require
- valid_index(index)
- do
- Result := storage.item(index - 1);
- end;
-
- valid_index(index: INTEGER): BOOLEAN is
- -- True when `index' is valid (ie inside actual bounds).
- do
- Result := 1 <= index and then index <= count;
- ensure
- Result = (1 <= index and index <= count)
- end;
-
- hash_code: INTEGER is
- do
- Result := storage.hashcode(count - 1);
- end;
-
- infix "<" (other: like Current): BOOLEAN is
- -- Is Current less than `other' ?
- local
- i: INTEGER;
- do
- from
- i := 1;
- until
- count < i or else other.count < i
- or else item(i) /= other.item(i)
- loop
- i := i + 1;
- end;
- if count < i then
- Result := other.count >= i;
- elseif other.count < i then
- Result := false;
- else
- Result := item(i) < other.item(i);
- end;
- end;
-
- compare(other: STRING): INTEGER is
- local
- i: INTEGER;
- do
- from
- i := 1;
- until
- count < i or else other.count < i
- or else item(i) /= other.item(i)
- loop
- i := i + 1;
- end;
- if count < i then
- if other.count < i then
- Result := 0;
- else
- Result := -1;
- end;
- elseif other.count < i then
- Result := +1;
- elseif item(i) < other.item(i) then
- Result := -1;
- else
- Result := +1;
- end;
- end;
-
- same_as(other: STRING): BOOLEAN is
- -- No difference is done between upper and lower case.
- local
- i: INTEGER;
- do
- if other = Current then
- Result := true;
- else
- if other.count /= count then
- else
- from
- i := count;
- until
- (i = 0) or else (not item(i).same_as(other.item(i)))
- loop
- i := i - 1;
- end;
- Result := (i = 0);
- end;
- end;
- end;
-
- is_equal(other: like Current): BOOLEAN is
- -- Has Current the same text as `other'?
- do
- if Current = other then
- Result := true;
- elseif count = other.count then
- if count > 0 then
- Result := storage.fast_memcmp(other.storage,count);
- else
- Result := true;
- end;
- end;
- end;
-
- index_of(ch: CHARACTER): INTEGER is
- -- Gives the index of the first occurrence `ch' or
- -- `count + 1' if none.
- do
- Result := 1 + storage.fast_index_of(ch,count - 1);
- ensure
- (Result /= count + 1) implies (item(Result) = ch);
- end;
-
- index_of_string(other: STRING): INTEGER is
- -- Position of the first occurrence of `other'
- -- `count + 1' if none.
- require
- not other.empty
- local
- stop: BOOLEAN;
- i1, i2, i3: INTEGER;
- do
- from
- i1 := 1;
- i2 := other.count;
- i3 := i2;
- invariant
- i3 = i2 - i1 + 1;
- variant
- count - i1 + 1
- until
- Result /= 0
- loop
- if i2 > count then
- Result := count + 1;
- else
- from
- stop := false;
- invariant
- i3 = i2 - i1 + 1
- variant
- (i3 + i2)
- until
- stop
- loop
- if i3 = 0 then
- stop := true;
- Result := i1;
- elseif other.item(i3) /= item(i2) then
- stop := true;
- end;
- i3 := i3 - 1;
- i2 := i2 - 1;
- end;
- end;
- i1 := i1 + 1;
- i3 := other.count;
- i2 := i1 + i3 - 1;
- end;
- end;
-
- has(ch: CHARACTER): BOOLEAN is
- -- True if `ch' is in the STRING.
- do
- Result := index_of(ch) /= (count + 1);
- end;
-
- has_string(other: STRING): BOOLEAN is
- -- True if `other' is in the STRING.
- do
- Result := index_of_string(other) /= (count + 1);
- end;
-
- occurrences_of(c: CHARACTER): INTEGER is
- -- How many character `c' in the receiver.
- do
- Result := storage.fast_nb_occurrences(c,count - 1);
- ensure
- Result >= 0
- end;
-
- has_suffix(s: STRING): BOOLEAN is
- -- True if suffix of Current is `s'.
- require
- s /= Void;
- local
- i1, i2: INTEGER;
- do
- if s.count <= count then
- from
- i1 := count - s.count + 1;
- i2 := 1;
- until
- i1 > count or else
- i2 > s.count or else
- item(i1) /= s.item(i2)
- loop
- i1 := i1 + 1;
- i2 := i2 + 1;
- end;
- Result := i1 > count;
- end;
- end;
-
- has_prefix(p: STRING): BOOLEAN is
- -- True if prefix of Current is `p'.
- require
- p /= Void;
- local
- i: INTEGER;
- do
- if p.count <= count then
- from
- i := p.count;
- until
- i = 0 or else item(i) /= p.item(i)
- loop
- i := i - 1;
- end;
- Result := i = 0;
- end;
- end;
-
- feature -- Modification :
-
- clear is
- -- Clear out the current STRING.
- -- Note : internal `storage' memory not released.
- do
- count := 0;
- ensure
- count = 0;
- end;
-
- copy(other: like Current) is
- -- Copy `other' onto Current.
- do
- count := other.count;
- if count > 0 then
- if capacity = 0 then
- storage.malloc(count);
- capacity := count;
- elseif capacity < count then
- storage.realloc(storage,count);
- capacity := count;
- end;
- storage.copy_from(other.storage,count-1);
- end;
- ensure then
- count = other.count
- end;
-
- fill_with(c: CHARACTER) is
- -- Fill entire string with character `c'
- do
- storage.set_all_with(c,count - 1);
- end;
-
- fill_blank is
- -- Fill entire string with blanks
- do
- fill_with(' ');
- end;
-
- append(other: STRING) is
- -- Append `other' to Current.
- require
- other /= Void
- local
- i: INTEGER;
- do
- from
- i := 1;
- until
- i > other.count
- loop
- extend(other.item(i));
- i := i + 1;
- end;
- end;
-
- prepend(other: STRING) is
- -- Prepend `other' to Current
- require
- other /= Void
- local
- i, old_count: INTEGER;
- do
- old_count := count;
- from
- i := other.count;
- until
- i = 0
- loop
- extend(' ');
- i := i - 1;
- end;
- from
- i := count;
- until
- old_count = 0
- loop
- put(item(old_count),i);
- i := i - 1;
- old_count := old_count - 1;
- end;
- from
- i := other.count
- until
- i = 0
- loop
- put(other.item(i),i);
- i := i - 1;
- end;
- ensure
- count = other.count + old count
- end;
-
- put(ch: CHARACTER; index: INTEGER) is
- -- Put `ch' at position `index'.
- require
- valid_index(index)
- do
- storage.put(ch,index - 1);
- ensure
- item (index) = ch
- end;
-
- swap(i1, i2: INTEGER) is
- require
- valid_index(i1);
- valid_index(i2)
- local
- tmp: CHARACTER;
- do
- tmp := item(i1);
- put(item(i2),i1);
- put(tmp,i2);
- ensure
- item(i1) = old item(i2);
- item(i2) = old item(i1);
- end;
-
- insert(ch: CHARACTER; index: INTEGER) is
- -- Insert `ch' after position `index'.
- require
- 0 <= index and index <= count;
- local
- i: INTEGER;
- do
- from
- i := count;
- extend(' ');
- until
- i = index
- loop
- put(item(i),i + 1);
- i := i - 1;
- end;
- put(ch,index + 1);
- ensure
- item (index + 1) = ch
- end;
-
- shrink(low, up: INTEGER) is
- -- Keep only the slice `low' .. `up' or nothing
- -- when the slice is empty.
- require
- 1 <= low;
- low <= count;
- 1 <= up;
- up <= count;
- local
- i, i2: INTEGER;
- do
- if up < low then
- clear;
- elseif low = 1 then
- count := up;
- else
- from
- i := 1;
- i2 := low;
- until
- i2 > up
- loop
- put(item(i2),i);
- i := i + 1;
- i2 := i2 + 1;
- end;
- count := i - 1;
- end;
- ensure
- up > low implies count = up - low + 1;
- end;
-
- remove(index: INTEGER) is
- -- Remove character at position `index'.
- require
- valid_index(index)
- do
- remove_between(index,index);
- ensure
- count = (old count) - 1
- end;
-
- add_first(ch: CHARACTER) is
- -- Add `ch' at first position.
- local
- i: INTEGER;
- do
- from
- extend(' ');
- i := count;
- until
- i = 1
- loop
- put(item(i - 1),i);
- i := i - 1;
- end;
- put(ch,1);
- ensure
- count = 1 + old count;
- item(1) = ch
- end;
-
- add_last, extend(ch: CHARACTER) is
- -- Append `ch' to string
- do
- if capacity > count then
- elseif capacity = 0 then
- capacity := 32;
- storage.malloc(capacity);
- else
- capacity := 2 * capacity;
- storage.realloc(storage,capacity);
- end;
- count := count + 1;
- put(ch,count);
- ensure
- count = 1 + old count;
- item (count) = ch;
- end;
-
- precede(ch: CHARACTER) is
- -- Prepend `ch' to string
- local
- i: INTEGER;
- do
- from
- extend(' ');
- i := count;
- until
- i = 1
- loop
- put(item(i-1),i);
- i := i - 1;
- end;
- put(ch,1);
- ensure
- item (1) = ch
- end;
-
- to_lower is
- -- Convert all characters to lower case.
- local
- i: INTEGER;
- do
- from
- i := count;
- until
- i = 0
- loop
- put(item(i).to_lower,i);
- i := i - 1;
- end;
- end;
-
- to_upper is
- -- Convert all characters to upper case.
- local
- i: INTEGER;
- do
- from
- i := count;
- until
- i = 0
- loop
- put(item(i).to_upper,i);
- i := i - 1;
- end;
- end;
-
- remove_first(nb: INTEGER) is
- -- Remove `nb' first characters.
- require
- nb >= 0;
- count >= nb;
- do
- if nb > 0 then
- remove_between(1, nb)
- end;
- ensure
- count = (old count) - nb
- end;
-
- remove_last(nb: INTEGER) is
- -- Remove `nb' last characters.
- require
- 0 <= nb;
- nb <= count;
- do
- count := count - nb;
- ensure
- count = old count - nb
- end;
-
- remove_between(low, up : INTEGER) is
- -- Remove character between positions `low' and `up'.
- require
- valid_index(low);
- valid_index(up);
- low <= up
- local
- i : INTEGER;
- do
- from
- i := up;
- until
- i >= count
- loop
- put(item(i + 1), low + i - up);
- i := i + 1;
- end;
- count := count - (up - low + 1);
- ensure
- count = (old count) - (up - low + 1)
- end;
-
- remove_suffix(s: STRING) is
- -- Remove the suffix `s' of current string.
- require
- has_suffix(s);
- do
- remove_last(s.count);
- ensure
- old count = count + s.count
- end;
-
- remove_prefix(s: STRING) is
- -- Remove the prefix `s' of current string.
- require
- has_prefix(s);
- do
- remove_first(s.count);
- ensure
- old count = count + s.count
- end;
-
- left_adjust is
- -- Remove leading blanks.
- local
- i: INTEGER;
- do
- from
- until
- i + 1 > count or else item(i + 1) /= ' '
- loop
- i := i + 1;
- end;
- remove_first(i);
- ensure
- stripped: empty or else item (1) /= ' '
- end;
-
- right_adjust is
- -- Remove trailing blanks.
- do
- from
- until
- count = 0 or else item(count) /= ' '
- loop
- count := count - 1;
- end
- ensure
- stripped: empty or else item (count) /= ' '
- end;
-
- feature -- Features which don't modify the string
-
- first: CHARACTER is
- require
- not empty;
- do
- Result := item(1);
- end;
-
- last: CHARACTER is
- require
- not empty;
- do
- Result := item(count);
- end;
-
- feature -- Conversion :
-
- to_integer: INTEGER is
- -- Current must looks like an INTEGER.
- local
- i, state: INTEGER;
- cc: CHARACTER;
- minus: BOOLEAN;
- do
- -- state 0 : nothing read.
- -- state 1 : "+" or "-" read.
- -- state 2 : in the number.
- -- state 3 : after the number.
- -- state 4 : error.
- from
- i := 1;
- until
- i > count or else state = 4
- loop
- cc := item(i);
- inspect
- state
- when 0 then
- if cc.is_separator then
- elseif cc = '+' then
- state := 1;
- elseif cc = '-' then
- minus := true;
- state := 1;
- elseif cc.is_digit then
- Result := cc.value;
- state := 2;
- else
- state := 4;
- end;
- when 1 then
- if cc.is_separator then
- elseif cc.is_digit then
- Result := cc.value;
- state := 2;
- else
- state := 4;
- end;
- when 2 then
- if cc.is_digit then
- Result := (Result * 10) + cc.value;
- elseif cc.is_separator then
- state := 3;
- else
- state := 4;
- end;
- else -- state = 3
- if cc.is_separator then
- else
- state := 4;
- end;
- end;
- i := i + 1;
- end;
- debug
- if state = 4 then
- std_error.put_string("STRING.to_integer: %"");
- std_error.put_string(Current);
- std_error.put_string("%" is not an INTEGER.%N");
- end;
- end;
- if minus then
- Result := - Result;
- end;
- end;
-
- is_integer: BOOLEAN is
- -- Contents can be read as an INTEGER.
- local
- i, state: INTEGER;
- cc: CHARACTER;
- do
- -- state 0 : nothing read.
- -- state 1 : "+" or "-" read.
- -- state 2 : in the number.
- -- state 3 : after the number.
- -- state 4 : error.
- from
- i := 1;
- until
- i > count or else state = 4
- loop
- cc := item(i);
- inspect
- state
- when 0 then
- if cc.is_separator then
- elseif cc = '+' then
- state := 1;
- elseif cc = '-' then
- state := 1;
- elseif cc.is_digit then
- state := 2;
- else
- state := 4;
- end;
- when 1 then
- if cc.is_separator then
- elseif cc.is_digit then
- state := 2;
- else
- state := 4;
- end;
- when 2 then
- if cc.is_digit then
- elseif cc.is_separator then
- state := 3;
- else
- state := 4;
- end;
- else -- state = 3
- if cc.is_separator then
- else
- state := 4;
- end;
- end;
- i := i + 1;
- end;
- Result := state /= 4;
- end;
-
- is_bit: BOOLEAN is
- -- True iwhen the contents is a sequence of bits (mixed
- -- characters '0' and characters '1').
- do
- Result := occurrences_of('1') + occurrences_of('0') = count;
- end;
-
- to_real: REAL is
- -- Conversion to the corresponding REAL value.
- -- The string must looks like a REAL (or like an
- -- INTEGER because fractionnal part is optional).
- do
- Result := to_double.to_real;
- end;
-
- to_double: DOUBLE is
- -- Conversion to the corresponding DOUBLE value.
- -- The string must looks like a DOUBLE, like
- -- a REAL (or like an INTEGER because fractionnal
- -- part is optional).
- --
- -- Now call ANSI C sscanf.
- require
- count >= 1;
- do
- tmp_string.copy(Current);
- Result := tmp_string.ansi_c_sscanf;
- end;
-
- binary_to_integer: INTEGER is
- -- Assume there is enougth space in the INTEGER to store
- -- the corresponding decimal value.
- require
- is_bit
- local
- i: INTEGER;
- do
- check
- Integer_bits - 1 >= count
- end;
- from
- i := 1;
- until
- i > count
- loop
- if item(i) = '1' then
- Result := (2 * Result) + 1;
- else
- Result := 2 * Result;
- end;
- i := i + 1;
- end;
- end;
-
- feature -- Printing :
-
- out_in_tagged_out_memory is
- do
- tagged_out_memory.append(Current);
- end;
-
- fill_tagged_out_memory is
- do
- tagged_out_memory.append("count: ");
- count.append_in(tagged_out_memory);
- tagged_out_memory.append("capacity: ");
- capacity.append_in(tagged_out_memory);
- tagged_out_memory.append("storage: %"");
- tagged_out_memory.append(Current);
- tagged_out_memory.extend('%"');
- end;
-
- feature -- Other features :
-
- substring(low, up: INTEGER): like Current is
- -- Create a new string initialized with range `low'.. `up'.
- require
- 1 <= low;
- low <= up;
- up <= count;
- local
- i: INTEGER;
- do
- from
- !!Result.make(up - low + 1);
- i := low;
- until
- i > up
- loop
- Result.extend(item(i));
- i := i + 1;
- end;
- end;
-
- reverse is
- -- Reverse the string.
- local
- i1, i2: INTEGER;
- do
- from
- i1 := 1;
- i2 := count;
- until
- i1 >= i2
- loop
- swap(i1,i2);
- i1 := i1 + 1;
- i2 := i2 - 1;
- end;
- end;
-
- remove_all_occurrences(ch: CHARACTER) is
- -- Remove all occurrences of `ch'.
- local
- i, j: INTEGER;
- do
- from
- i := 1;
- j := 1;
- until
- i > count
- loop
- if item(i) /= ch then
- put(item(i),j);
- j := j + 1;
- end;
- i := i + 1;
- end;
- count := j - 1;
- ensure
- count = old count - old occurrences_of(ch)
- end;
-
- feature -- Splitting a STRING :
-
- split: ARRAY[STRING] is
- -- Split the string into an array of words.
- -- Uses `is_separator' of CHARACTER to find words.
- -- Gives Void or a non empty array.
- do
- if count > 0 then
- !!Result.with_capacity(4,1);
- split_in(Result);
- if Result.empty then
- Result.free;
- Result := Void;
- end;
- end;
- ensure
- Result /= Void implies not Result.empty
- end;
-
- split_in(words: COLLECTION[STRING]) is
- -- Same jobs as `split' but result is appended in `words'.
- require
- words /= Void
- local
- state, i: INTEGER;
- -- state = 0 : waiting next word.
- -- state = 1 : inside a new word.
- c: CHARACTER;
- do
- if count > 0 then
- from
- i := 1;
- until
- i > count
- loop
- c := item(i);
- if state = 0 then
- if not c.is_separator then
- tmp_string.clear;
- tmp_string.extend(c);
- state := 1;
- end;
- else
- if not c.is_separator then
- tmp_string.extend(c);
- else
- words.add_last(tmp_string.twin);
- state := 0;
- end;
- end;
- i := i + 1;
- end;
- if state = 1 then
- words.add_last(tmp_string.twin);
- end;
- end;
- ensure
- words.count >= old (words.count)
- end;
-
- feature -- Interfacing with C string :
-
- to_external: POINTER is
- -- Gives C access to the internal storage of STRING.
- -- To be compatible with C, a null character is always
- -- appended at the end of internal storage.
- -- The added null character is not part of the Eiffel STRING.
- --
- -- NOTE: do not free/realloc the Result.
- do
- if capacity > count then
- count := count + 1;
- if item(count) /= '%U' then
- put('%U',count);
- end;
- else
- extend('%U');
- end;
- count := count - 1;
- Result := storage.to_pointer;
- ensure
- Result.is_not_void
- end;
-
- from_external(p: POINTER) is
- -- Assume `p' is the addresse of a C string.
- -- Initialize the string using `p'.
- -- The null character is not part of the Eiffel STRING.
- require
- p.is_not_void
- do
- if storage.to_pointer.is_not_void then
- storage.free;
- end;
- from
- storage.from_pointer(p);
- capacity := 1;
- count := 1;
- until
- item(capacity) = '%U'
- loop
- capacity := capacity + 1;
- count := capacity;
- end;
- count := count - 1;
- ensure
- capacity = count + 1;
- p = to_external
- end;
-
- feature -- Other feature :
-
- set_last(ch: CHARACTER) is
- do
- if count = 0 or else item(count) /= ch then
- extend(ch);
- end;
- ensure
- last = ch
- end;
-
- feature -- Other feature here for ELKS95 compatibility :
-
- head(n: INTEGER) is
- -- Remove all characters except fo the first `n'.
- -- Do nothing if n >= count.
- require
- n >= 0
- do
- if n < count then
- remove_last(count - n);
- end;
- ensure
- count = n.min(old count)
- end;
-
- tail(n: INTEGER) is
- -- Remove all characters except for the last `n'.
- -- Do nothing if n >= count.
- require
- n >= 0
- do
- if n < count then
- remove_first(count - n);
- end;
- ensure
- count = n.min(old count)
- end;
-
- feature -- The Guru section :
-
- free is
- local
- mem: MEMORY;
- do
- if storage.to_pointer.is_not_void then
- storage.free;
- end;
- mem.free(Current.to_pointer);
- end;
-
- feature {STRING}
-
- ansi_c_sscanf: DOUBLE is
- local
- negative: BOOLEAN;
- do
- left_adjust;
- if count > 0 then
- if first = '-' then
- negative := true;
- remove_first(1);
- left_adjust;
- elseif first = '+' then
- remove_first(1);
- left_adjust;
- end;
- end;
- if count > 0 then
- extend('%/0/');
- c_inline_c("sscanf(C->_storage,%"%%lf%",&R);");
- if negative then
- Result := - Result;
- end;
- end;
- end;
-
- feature {DOUBLE}
-
- ansi_c_sprintf(value: DOUBLE; fmt: STRING) is
- do
- c_inline_c("sprintf(C->_storage,((T7*)a2)->_storage,a1);");
- from
- count := 1;
- until
- last = '%/0/'
- loop
- count := count + 1;
- end;
- count := count - 1;
- end;
-
- feature {NONE}
-
- tmp_string: STRING is
- once
- !!Result.make(256);
- end;
-
- invariant
-
- 0 <= count;
-
- count <= capacity;
-
- capacity > 0 implies storage.is_not_void;
-
- end -- STRING
-